<script setup lang="ts">
import sparkMD5 from 'spark-md5'
import axios from 'axios'
import { ref } from 'vue';

// const config_json = {
//   headers: {
//     'Content-Type': 'application/json',
//   },
//   processData: false,
// };

// const config_flase = {
//   headers: {
//     'Content-Type': false,
//   },
//   processData: false,
// };
const upload = ref<HTMLInputElement>()
/**
 * 获取文件MD5
 * @param file
 * @returns {Promise<unknown>}
 */
const getFileMd5 = (file: Blob) => {
  let fileReader = new FileReader()
  fileReader.readAsBinaryString(file)
  let spark = new sparkMD5()
  return new Promise((resolve) => {
    fileReader.onload = (e) => {
      spark.appendBinary(e.target!.result as string)
      resolve(spark.end())
    }
  })
}

//分片大小 8mb
const chunkSize = 8 * 1024 * 1024;

const uploadFile = async () => {
  //获取用户选择的文件
  const file = upload.value!.files![0];
  //文件大小(大于5m再分片哦，否则直接走普通文件上传的逻辑就可以了，这里只实现分片上传逻辑)
  const fileSize = file.size

  if (fileSize <= chunkSize) {
    console.log("上传的文件大于8m才能分片上传")
  }

  //计算当前选择文件需要的分片数量
  const chunkCount = Math.ceil(fileSize / chunkSize)
  console.log("文件大小：", (file.size / 1024 / 1024) + "Mb", "分片数：", chunkCount)

  //获取文件md5
  const fileMd5 = await getFileMd5(file);
  console.log("文件md5：", fileMd5)

  console.log("向后端请求本次分片上传初始化")
  //向后端请求本次分片上传初始化
  const initUploadParams = { chunkSize: chunkCount, fileName: file.name, bucket: 'test' }
  console.log('初始化分片请求参数：', initUploadParams)
  axios("http://127.0.0.1:8080/file/multipart/create", {
    method: 'POST',
    headers: { contentType: "application/json" }, 
    data: initUploadParams
  }).then(async function (resp) {
    const res = resp.data
    console.log('status code:', res.code)
    //code = 0 文件在之前已经上传完成，直接走秒传逻辑；code = 1 文件上传过，但未完成，走续传逻辑;code = 200 则仅需要合并文件
    if (res.code === 20000) {
      console.log("当前文件上传情况：所有分片已在之前上传完成，仅需合并")
      composeFile(res.data.uploadId, file.name, chunkCount, fileSize, file.type)
      return;
    }
    
    // TODO: fix
    if (res.code === 0) {
      console.log("当前文件上传情况：秒传")
      return
    }

    console.log("当前文件上传情况：初次上传 或 断点续传")
    const chunkUploadUrls = res.data.chunks
    for (const item of chunkUploadUrls) {
      //分片开始位置
      let start = (item.partNumber - 1) * chunkSize
      //分片结束位置
      let end = Math.min(fileSize, start + chunkSize)
      //取文件指定范围内的byte，从而得到分片数据
      let _chunkFile = file.slice(start, end)
      console.log("开始上传第" + item.partNumber + "个分片", "上传地址为：" + item.uploadUrl)
      //console.log(`上传第${item.partNumber}个分片的请求参数：`, _chunkFile)
      await axios.put(item.uploadUrl, _chunkFile).then((res) => {
        console.log("第" + item.partNumber + "个分片上传完成")
      }).catch(err => console.log(err))
    }
    //请求后端合并文件
    composeFile(res.data.uploadId, file.name, chunkCount, fileSize, file.type)
  }).catch(err => console.log(err))
}

/**
 * 请求后端合并文件
 * @param fileMd5
 * @param fileName
 */
const composeFile = (uploadId: string, fileName: string, chunkSize: number, fileSize: number, contentType: string) => {
  console.log("开始请求后端合并文件")
  //注意：bucketName请填写你自己的存储桶名称，如果没有，就先创建一个写在这
  const composeParams = { uploadId: uploadId, fileName: fileName, chunkSize: chunkSize, fileSize: fileSize, contentType: contentType, expire: 12, maxGetCount: 2, bucket: 'test' }
  console.log('和并请求参数：', composeParams)
  axios("http://127.0.0.1:8080/file/multipart/complete", { method: 'POST', headers: { contentType: "application/json" }, data: composeParams, }).then(res => {
    console.log("合并文件完成", res.data)
  }).catch(err => console.log(err))
}
</script>

<template>
  <div>
    <input type="file" ref="upload" @change="uploadFile">
  </div>
</template>
